<template>
  <div>
    <el-card>
      <h1 style="width: 20%; margin: auto">算法介绍</h1>
      <p style="font-size: large">
        聚类（Clustering） 是一种无监督学习技术，旨在将数据集中的样本划分为若干组（称为“簇”），使得同一簇内的样本相似度较高，而不同簇之间的样本差异较大。它的核心目标是发现数据的内在结构，无需依赖标签信息。K-means将数据划分为预定义数量（K）的簇，通过迭代优化目标函数（如最小化样本到簇中心的距离）。
      </p>
      <el-table
        :data="tableData"
        style="width: 100%">
        <el-table-column
          prop="name"
          label="算法分析指标"
          width="180">
        </el-table-column>
        <el-table-column
          prop="mean"
          label="定义"
          width="180">
        </el-table-column>
        <el-table-column
          prop="count"
          label="算式">
        </el-table-column>
        <el-table-column
          prop="earn"
          label="意义">
        </el-table-column>
      </el-table>
    </el-card>

    <el-card>
      <h1 style="width: 20%; margin: auto">数据集选择</h1>
      <el-select v-model="courseSelect" filterable placeholder="请选择课程" style="width: 10%; margin: 2%">
        <el-option
          v-for="item in courseOptions"
          :key="item.subId"
          :label="item.subName"
          :value="item.subId">
        </el-option>
      </el-select>
      <el-select v-model="classSelect" filterable placeholder="请选择班级" style="width: 10%; margin: 2%">
        <el-option
          v-for="item in classOptions"
          :key="item.classId"
          :label="item.className"
          :value="item.classId"/>
      </el-select>
      <el-select v-model="clusterCount" filterable placeholder="聚类数量" style="width: 10%; margin: 2%">
        <el-option
          v-for="item in clusterOptions"
          :key="item"
          :value="item">
        </el-option>
      </el-select>
      <el-button type="primary" @click="clusterAnalyse" style="width: 10%; margin: 2%">开始分析</el-button>
    </el-card>

    <el-card v-if="show">
      <h1 style="width: 20%; margin: auto">分析图表</h1>
      <div
        ref="myChart"
        id="myChart"
        class="chart-box"
        :style="{ width: '800px', height: '800px' }"
        style="margin: auto"
      >
      </div>
    </el-card>

    <el-card v-if="show">
      <h1 style="width: 20%; margin: auto">分析结果说明</h1>
      <el-table
        :data="valuesTable"
        style="width: 100%"
      >
        <el-table-column
          prop="center"
          label="聚类中心点"
          style="width: 20%; margin: auto"
        />
        <el-table-column
          prop="count"
          label="聚类中学生数量"
          sortable
          style="width: 20%; margin: auto"
        />
        <el-table-column
          prop="countRange"
          label="聚类中学生占比"
          style="width: 20%; margin: auto"
        />
        <el-table-column
          prop="courseRange"
          label="聚类课程成绩范围"
          style="width: 20%; margin: auto"
        />
        <el-table-column
          prop="studentRange"
          label="聚类学生评教成绩范围"
          style="width: 20%; margin: auto"
        />
      </el-table>
    </el-card>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import ecStat from 'echarts-stat'
import axios from 'axios'
import { clustering } from 'echarts-stat'

export default {
  data() {
    return {
      clusterStats: [],
      clusterData: [],
      classOptions: [],
      courseOptions: [],
      clusterOptions: [],
      clusterCount: '聚类数量',
      classSelect: '',
      courseSelect: '',
      valuesTable: [],
      tableData: [
        {
          name: '聚类中心点',
          mean: '聚类中心点是每个簇的代表性点，通常通过计算簇内所有数据点的均值得到。',
          count: '假设二维数据簇 C1 包含点 (1,2),(2,3),(3,1)，则中心点为：u = ( 1+2+3/3, 2+3+1/3 ) = (2,2)',
          earn: '中心点反映簇内数据的“平均位置”，是簇内所有点的“平衡点”。'
        },
        {
          name: '聚类数',
          mean: '聚类数（通常记为 K）是人为设定的参数，表示将数据划分为多少个簇。',
          count: '作为算法参数，提供接口人为定义。',
          earn: 'K 过小：簇内差异大，可能忽略真实结构。K 过大：簇间差异小，可能导致过拟合。'
        }
      ],
      show: false
    }
  },
  methods: {
    async getCourseOptions() {
      await axios.get('http://localhost:8080/course/get_all').then((res) => {
        for (let i = 0; i < res.data.data.length; i++) {
          this.courseOptions[i] = {
            subName: '',
            subId: ''
          }
          this.courseOptions[i].subName = res.data.data[i].subName
          this.courseOptions[i].subId = res.data.data[i].subId
        }
        this.courseOptions[this.courseOptions.length - 1].subName = 'ALL'
        this.courseOptions[this.courseOptions.length - 1].subId = 'ALL'
        this.courseSelect = '请选择课程'
      })
    },
    async getClassOptions() {
      await axios.get('http://localhost:8080/class/get_all').then((res) => {
        for (let i = 0; i < res.data.data.length; i++) {
          this.classOptions[i] = {
            className: '',
            classId: ''
          }
          this.classOptions[i].className = res.data.data[i].className
          this.classOptions[i].classId = res.data.data[i].classId
        }
        this.classOptions[this.classOptions.length - 1].className = 'ALL'
        this.classOptions[this.classOptions.length - 1].classId = 'ALL'
        this.classSelect = '请选择班级'
      })
    },
    async getScoreSet() {
      if (this.courseSelect === '请选择课程' || this.courseSelect === 'ALL') {
        this.courseSelect = null
      }
      if (this.classSelect === '请选择班级' || this.classSelect === 'ALL') {
        this.classSelect = null
      }

      const params = new URLSearchParams()
      params.append('classId', this.classSelect)
      params.append('subId', this.courseSelect)
      params.append('clusterNum', this.clusterCount)
      console.log(this.classSelect)
      console.log(this.courseSelect)

      await axios.post('http://localhost:8080/cluster_score/cluster', params, {
        headers: {
          'Content-Type': 'application/x-www-form-urlencoded' // 必须指定 Content-Type
        }
      }).then((res) => {
        // 未查询到相关数据进行提示
        if (res.data.success === false) {
          this.$message.error('未查询到相关数据')
          return
        }

        this.show = true
        this.clusterData = res.data.data
        console.log(res)
        if (res.data.success === false) {
          this.$message.error('未查询到相关数据')
        }
      })
    },
    async clusterAnalyse() {
      await this.getScoreSet()

      if (this.clusterData.length === 0) {
        return
      }

      const dom = this.$refs['myChart'] // 获取dom节点
      const myChart = echarts.init(dom) // 初始化echarts实例
      // const myChart = echarts.init(document.getElementById('myChart'))
      echarts.registerTransform(ecStat.transform.clustering)

      // 创建一个二维数组
      const array = new Array(this.clusterData.length)
      for (let i = 0; i < array.length; i++) {
        array[i] = new Array(2) // 每行创建长度为2的子数组

        // 为子数组赋值（例如随机数）
        array[i][0] = parseFloat(this.clusterData[i].score)
        array[i][1] = parseFloat(this.clusterData[i].evaScore)
      }

      // 找到坐标轴范围
      let xMin = Infinity
      let xMax = -Infinity
      let yMin = Infinity
      let yMax = -Infinity
      for (const point of array) {
        const x = point[0]
        const y = point[1]

        // 更新 X 轴极值
        if (x < xMin) xMin = x
        if (x > xMax) xMax = x

        // 更新 Y 轴极值
        if (y < yMin) yMin = y
        if (y > yMax) yMax = y
      }

      // const CLUSTER_COUNT = 4
      const DIENSIION_CLUSTER_INDEX = 2
      const COLOR_ALL = [
        '#37A2DA',
        '#e06343',
        '#37a354',
        '#b55dba',
        '#b5bd48',
        '#8378EA',
        '#96BFFF'
      ]
      const pieces = []
      for (let i = 0; i < this.clusterCount; i++) {
        pieces.push({
          value: i,
          label: '聚类 ' + (i + 1),
          color: COLOR_ALL[i]
        })
      }

      const kmeansResult = ecStat.clustering.hierarchicalKMeans(array, {
        clusterCount: this.clusterCount, // 聚类数量
        outputClusterIndexDimension: 2
        // outputType: 'single', // 输出类型（'single' 或 'all'）
        // stepByStep: false // 是否逐步执行（调试用）
      })
      console.log(kmeansResult)

      console.log('聚类中心:', kmeansResult.centroids)
      // console.log('聚类结果:', array)
      // 输出示例: [[x1, y1], [x2, y2], [x3, y3]]

      // 获取聚类后的数据点集合（二维数组的数组）
      const pointsInClusters = kmeansResult.pointsInCluster
      const centers = kmeansResult.centroids // 中心点坐标
      console.log(pointsInClusters)

      this.clusterStats = pointsInClusters.map((clusterPoints, clusterIndex) => {
        // 中心点取一位小数
        kmeansResult.centroids[clusterIndex][0] = Math.round(kmeansResult.centroids[clusterIndex][0] * 10) / 10
        kmeansResult.centroids[clusterIndex][1] = Math.round(kmeansResult.centroids[clusterIndex][1] * 10) / 10

        // 提取当前聚类的所有 X 和 Y 值
        const xValues = clusterPoints.map(point => point[0])
        const yValues = clusterPoints.map(point => point[1])

        // 计算极值
        const xMin = Math.min(...xValues)
        const xMax = Math.max(...xValues)
        const yMin = Math.min(...yValues)
        const yMax = Math.max(...yValues)

        return {
          clusterIndex: clusterIndex,
          count: clusterPoints.length, // 点的数量
          xRange: [Math.round(xMin * 10) / 10, Math.round(xMax * 10) / 10], // X轴范围
          yRange: [Math.round(yMin * 10) / 10, Math.round(yMax * 10) / 10], // Y轴范围
          centroid: kmeansResult.centroids[clusterIndex] // 聚类中心
        }
      })

      // const option = {
      //   dataset: [
      //     {
      //       source: array
      //     },
      //     {
      //       transform: {
      //         type: 'ecStat:clustering',
      //         // print: true,
      //         config: {
      //           clusterCount: this.clusterCount,
      //           outputType: 'single',
      //           outputClusterIndexDimension: DIENSIION_CLUSTER_INDEX
      //         }
      //       }
      //     }
      //   ],
      //   tooltip: {
      //     position: 'top'
      //   },
      //   visualMap: {
      //     type: 'piecewise',
      //     top: 'middle',
      //     min: 0,
      //     max: this.clusterCount,
      //     left: 10,
      //     splitNumber: this.clusterCount,
      //     dimension: DIENSIION_CLUSTER_INDEX,
      //     pieces: pieces
      //   },
      //   grid: {
      //     left: 120
      //   },
      //   xAxis: { name: '学生成绩', type: 'value', min: Math.floor(xMin), max: Math.ceil(xMax) },
      //   yAxis: { name: '评教成绩', type: 'value', min: Math.floor(yMin), max: Math.ceil(yMax) },
      //   series: [
      //     {
      //       type: 'scatter',
      //       encode: { tooltip: [0, 1] },
      //       symbolSize: 15,
      //       itemStyle: {
      //         borderColor: '#555'
      //       },
      //       datasetIndex: 1
      //     },
      //     {
      //       type: 'scatter',
      //       data: centers,
      //       symbol: 'triangle',
      //       symbolSize: 20,
      //       itemStyle: { color: '#FF0000' }
      //     }
      //   ]
      // }
      // 设置实例参数
      // myChart.setOption(option)

      myChart.setOption({
        tooltip: { trigger: 'item' },
        xAxis: { name: '学生成绩', type: 'value', min: Math.floor(xMin), max: Math.ceil(xMax) },
        yAxis: { name: '评教成绩', type: 'value', min: Math.floor(yMin), max: Math.ceil(yMax) },
        legend: { data: pointsInClusters.map((_, i) => `聚类 ${i + 1}`) },
        series: pointsInClusters.map((cluster, index) => ({
          type: 'scatter',
          encode: { tooltip: [0, 1] },
          name: `聚类 ${index + 1}`,
          data: cluster,
          itemStyle: {
            color: ['#37A2DA',
              '#e06343',
              '#37a354',
              '#b55dba',
              '#b5bd48',
              '#8378EA',
              '#96BFFF'][index % 5],
            opacity: 0.8
          },
          symbolSize: 20
        }))
      })

      // 点击事件监听
      myChart.on('click', (params) => {
        // params.data 包含当前点击点的完整数据
        console.log('点击数据：', params.data)
        // 示例输出：{ value: [x, y, clusterId], ... }
      })

      // console.log(option)
      // console.log(111)

      this.valuesTable = []
      let total = 0
      for (let i = 0; i < this.clusterStats.length; ++i) {
        total += this.clusterStats[i].count
      }
      for (let i = 0; i < this.clusterStats.length; ++i) {
        this.valuesTable[i] = {
          center: '(' + this.clusterStats[i].centroid[0] + ', ' + this.clusterStats[i].centroid[1] + ')',
          count: this.clusterStats[i].count,
          countRange: Math.round(this.clusterStats[i].count / total * 100) + '%',
          courseRange: '[' + this.clusterStats[i].xRange[0] + '~' + this.clusterStats[i].xRange[1] + ']',
          studentRange: '[' + this.clusterStats[i].yRange[0] + '~' + this.clusterStats[i].yRange[1] + ']'
        }
      }

      console.log(this.valuesTable)

      console.log('聚类统计信息:', this.clusterStats)
    },
    fetchData() {
      // 异步获取数据后更新响应式变量
      this.clusterData = processedData
      console.log(this.clusterData)
      console.log(111)
    },
    async clusterAnalyseTemp() {
      await this.getScoreSet()
      if (this.clusterData.length === 0) {
        return
      }

      // 创建一个二维数组
      const array = new Array(this.clusterData.length)
      for (let i = 0; i < array.length; i++) {
        array[i] = new Array(2) // 每行创建长度为2的子数组

        // 为子数组赋值（例如随机数）
        array[i][0] = parseFloat(this.clusterData[i].score)
        array[i][1] = parseFloat(this.clusterData[i].evaScore)
      }

      const kmeansResult = clustering.hierarchicalKMeans(array, {
        clusterCount: this.clusterCount,
        outputClusterIndexDimension: 2
      })

      const seriesData = []
      let index = 0
      for (let i = 0; i < kmeansResult.pointsInCluster.length; i++) {
        for (let j = 0; j < kmeansResult.pointsInCluster[i].length; j++) {
          seriesData[index] = {
            value: [kmeansResult.pointsInCluster[i][j][0], kmeansResult.pointsInCluster[i][j][1]],
            cluster: i
          }
          ++index
        }
      }
      console.log(seriesData)

      const option = {
        dataset: [{
          source: seriesData,
          dimensions: ['x', 'y', 'cluster']
        }],
        xAxis: { type: 'value', scale: true },
        yAxis: { type: 'value', scale: true },
        visualMap: {
          type: 'piecewise',
          dimension: 2,
          categories: [...new Set(seriesData.map(d => d.cluster))],
          inRange: { color: ['#5470c6', '#91cc75', '#fac858'] }
        },
        series: [
          { // 主数据点
            type: 'scatter',
            encode: { x: 0, y: 1 },
            symbolSize: 12,
            itemStyle: { borderColor: '#333', borderWidth: 1 }
          }
        ],
        tooltip: {
          formatter: params => `Cluster ${params.value[2]}<br>
      X: ${params.value[0].toFixed(2)}<br>
      Y: ${params.value[1].toFixed(2)}`
        }
      }

      const chart = echarts.init(document.getElementById('myChart'))
      chart.setOption(option)
    },
    async clusterAnalyse2() {
      await this.getScoreSet()
      if (this.clusterData.length === 0) {
        return
      }

      // 展示分析结果
      this.show = true

      // 创建一个二维数组
      const array = new Array(this.clusterData.length)
      for (let i = 0; i < array.length; i++) {
        array[i] = new Array(2) // 每行创建长度为2的子数组

        // 为子数组赋值（例如随机数）
        array[i][0] = parseFloat(this.clusterData[i].score)
        array[i][1] = parseFloat(this.clusterData[i].evaScore)
      }

      // 执行聚类（分为3类）
      const kmeansResult = ecStat.clustering.hierarchicalKMeans(array, {
        clusterCount: this.clusterCount,
        outputClusterIndexDimension: 2 // 聚类索引写入第3个维度（不影响原始数据）
      })

      // 提取结果
      const clusterAssment = kmeansResult.clusterAssment // 聚类索引数组
      const centers = kmeansResult.centroids // 中心点坐标

      // 配置 ECharts
      const option = {
        xAxis: { type: 'value' },
        yAxis: { type: 'value' },
        series: [
          // 原始数据点系列
          {
            type: 'scatter',
            data: array,
            symbolSize: 10,
            itemStyle: {
              color: (params) => {
                const COLOR_ALL = [
                  '#37A2DA',
                  '#e06343',
                  '#37a354',
                  '#b55dba',
                  '#b5bd48',
                  '#8378EA',
                  '#96BFFF'
                ]
                const clusterIndex = clusterAssment[params.dataIndex]
                return COLOR_ALL[clusterIndex]
              }
            }
          },
          // 聚类中心系列
          {
            type: 'scatter',
            data: centers,
            symbol: 'triangle',
            symbolSize: 20,
            itemStyle: { color: '#FF0000' }
          }
        ]
      }

      // 渲染图表
      const chart = echarts.init(document.getElementById('myChart'))
      chart.setOption(option)
    },
    async clusterAnalyse3() {
      await this.getScoreSet()
      if (this.clusterData.length === 0) {
        return
      }

      // 展示分析结果
      this.show = true

      // 创建一个二维数组
      const array = new Array(this.clusterData.length)
      for (let i = 0; i < array.length; i++) {
        array[i] = new Array(2) // 每行创建长度为2的子数组

        // 为子数组赋值（例如随机数）
        array[i][0] = parseFloat(this.clusterData[i].score)
        array[i][1] = parseFloat(this.clusterData[i].evaScore)
      }

      // 2. 执行聚类（但完全不使用聚类结果）
      const kmeansResult = ecStat.clustering.hierarchicalKMeans(
        JSON.parse(JSON.stringify(array)), // 深拷贝保护原始数据
        { clusterCount: this.clusterCount }
      )

      // 提取结果
      const clusterAssment = kmeansResult.clusterAssment // 聚类索引数组
      // const centers = kmeansResult.centroids // 中心点坐标

      // 3. 直接渲染原始数据（不依赖聚类结果）
      const option = {
        xAxis: { type: 'value' },
        yAxis: { type: 'value' },
        series: [{
          type: 'scatter',
          data: array, // 直接使用原始二维数据
          symbolSize: 20,
          itemStyle: {
            color: (params) => {
              const COLOR_ALL = [
                '#37A2DA',
                '#e06343',
                '#37a354',
                '#b55dba',
                '#b5bd48',
                '#8378EA',
                '#96BFFF'
              ]
              const clusterIndex = clusterAssment[params.dataIndex]
              return COLOR_ALL[clusterIndex]
            }
          }
        }]
      }

      // 4. 渲染并验证
      const chart = echarts.init(document.getElementById('myChart'))
      chart.setOption(option)

      // 5. 控制台输出验证（关键步骤）
      console.log('原始数据:', array)
      console.log('图表配置:', option)
    }
  },
  watch: {
    valuesTable: {
      handler() {
        this.$forceUpdate()
      },
      deep: true // 深度监听所有嵌套属性
    }
  },
  mounted() {
    this.clusterOptions = ['3', '4', '5', '6', '7']

    this.getCourseOptions()
    this.getClassOptions()
  }
}
</script>

<style>
.chart-container {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 20px;
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}
.chart-box {
  height: 800px;
  width: 800px;
  border: 1px solid #eee;
  padding: 15px;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
</style>
